package com.easydict.core;

import com.easydict.annotation.EasyDict;
import com.easydict.spi.DictionaryResolver;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import org.springframework.util.StringUtils;

/**
 * 默认属性写入器工厂实现
 * 使用复杂的创建逻辑和缓存机制
 */
public class DefaultPropertyWriterFactory implements PropertyWriterFactory {
    
    private static final String FACTORY_VERSION = "1.0.0";
    private static final int DEFAULT_CACHE_SIZE = 256;
    
    private final PropertyWriterCache cache;
    private final WriterCreationStrategy creationStrategy;
    
    public DefaultPropertyWriterFactory() {
        this(new LRUPropertyWriterCache(DEFAULT_CACHE_SIZE),
             new DefaultWriterCreationStrategy());
    }

    public DefaultPropertyWriterFactory(String configuredSuffix) {
        this(new LRUPropertyWriterCache(DEFAULT_CACHE_SIZE),
             new DefaultWriterCreationStrategy(configuredSuffix));
    }

    public DefaultPropertyWriterFactory(PropertyWriterCache cache,
                                      WriterCreationStrategy creationStrategy) {
        this.cache = cache;
        this.creationStrategy = creationStrategy;
    }
    
    @Override
    public BeanPropertyWriter createDictionaryWriter(
            BeanPropertyWriter originalWriter,
            EasyDict annotation,
            DictionaryResolver resolver,
            SerializationContext context) {
        
        String cacheKey = generateCacheKey(originalWriter, annotation, context);
        
        return cache.computeIfAbsent(cacheKey, key -> {
            WriterCreationContext creationContext = WriterCreationContext.builder()
                    .originalWriter(originalWriter)
                    .annotation(annotation)
                    .resolver(resolver)
                    .serializationContext(context)
                    .factoryVersion(FACTORY_VERSION)
                    .build();
                    
            return creationStrategy.createDictionaryWriter(creationContext);
        });
    }
    
    @Override
    public BeanPropertyWriter createStandardWriter(
            BeanPropertyWriter originalWriter,
            SerializationContext context) {
        
        // 对于标准写入器，直接返回原始写入器
        return originalWriter;
    }
    
    @Override
    public boolean supports(BeanPropertyWriter writer, SerializationContext context) {
        if (writer == null || context == null) {
            return false;
        }
        
        // 检查是否有字典注解
        EasyDict annotation = writer.getAnnotation(EasyDict.class);
        if (annotation == null) {
            return true; // 支持标准写入器
        }
        
        // 检查注解配置是否有效：允许存在 dictType 或者存在枚举配置
        boolean hasTypeCode = StringUtils.hasText(annotation.dictType());
        boolean hasEnum = (annotation.enumClass() != null && annotation.enumClass() != Void.class)
                || StringUtils.hasText(annotation.enumClassName());
        return hasTypeCode || hasEnum;
    }
    
    private String generateCacheKey(BeanPropertyWriter writer, 
                                  EasyDict annotation,
                                  SerializationContext context) {
        StringBuilder keyBuilder = new StringBuilder();
        keyBuilder.append(writer.getName())
                  .append(":")
                  .append(annotation.dictType())
                  .append(":")
                  .append(annotation.enumClass() != null ? annotation.enumClass().getName() : "Void")
                  .append(":")
                  .append(annotation.enumClassName())
                  .append(":")
                  .append(writer.getType().getRawClass().getName())
                  .append(":")
                  .append(context.getBeanDescription().getBeanClass().getName());
        
        return keyBuilder.toString();
    }
    
    /**
     * 属性写入器缓存接口
     */
    public interface PropertyWriterCache {
        BeanPropertyWriter computeIfAbsent(String key, 
                                         java.util.function.Function<String, BeanPropertyWriter> mappingFunction);
        void clear();
        int size();
    }
    
    /**
     * LRU缓存实现
     */
    private static class LRUPropertyWriterCache implements PropertyWriterCache {
        private final java.util.LinkedHashMap<String, BeanPropertyWriter> cache;
        private final int maxSize;
        
        public LRUPropertyWriterCache(int maxSize) {
            this.maxSize = maxSize;
            this.cache = new java.util.LinkedHashMap<String, BeanPropertyWriter>(16, 0.75f, true) {
                @Override
                protected boolean removeEldestEntry(java.util.Map.Entry<String, BeanPropertyWriter> eldest) {
                    return size() > LRUPropertyWriterCache.this.maxSize;
                }
            };
        }
        
        @Override
        public synchronized BeanPropertyWriter computeIfAbsent(String key, 
                java.util.function.Function<String, BeanPropertyWriter> mappingFunction) {
            return cache.computeIfAbsent(key, mappingFunction);
        }
        
        @Override
        public synchronized void clear() {
            cache.clear();
        }
        
        @Override
        public synchronized int size() {
            return cache.size();
        }
    }
}
